package com.jingtuo.android.common.db;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

import com.jingtuo.android.common.db.annotation.Column;
import com.jingtuo.android.common.db.annotation.Table;
import com.jingtuo.android.common.helper.DateTimeHelper;
import com.jingtuo.android.common.helper.StringHeper;
import com.jingtuo.android.common.utils.LogUtils;

import android.content.ContentValues;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;

/**
 * <pre>
 * 字段类型:
 * 暂时未对枚举类型进行处理
 * 表操作-新增字段:
 * 要求Table新增的Column添加通过@Column注释指定version,每次变更通过数据库版本号变更来维护
 * </pre>
 * @author 28173_000
 *
 */
public class SqliteHelper extends SQLiteOpenHelper {
	
	public static final String TAG = SqliteHelper.class.getName();
	
	/**
	 * The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE).
	 */
	public static final String DATA_TYPE_TEXT = "TEXT";
	
	/**
	 * 
	 */
	public static final String DATA_TYPE_NULL = "NULL";
	
	/**
	 * The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.
	 */
	public static final String DATA_TYPE_INTEGER = "INTEGER";
	
	/**
	 * The value is a floating point value, stored as an 8-byte IEEE floating point number.
	 */
	public static final String DATA_TYPE_REAL = "REAL";
	
	/**
	 * The value is a blob of data, stored exactly as it was input.
	 */
	public static final String DATA_TYPE_BLOD = "BLOD";

	private OnSqliteListener onSqliteListener;

	public SqliteHelper(Context context, String name, CursorFactory factory,
			int version, DatabaseErrorHandler errorHandler) {
		super(context, name, factory, version, errorHandler);
		// TODO Auto-generated constructor stub
	}

	public SqliteHelper(Context context, String name, CursorFactory factory,
			int version) {
		super(context, name, factory, version);
		// TODO Auto-generated constructor stub
	}

	/**
	 * 
	 * @param config 必须设置:context,name,version
	 * @param onSqliteListener
	 */
	public SqliteHelper(SqliteConfig config, OnSqliteListener onSqliteListener){
		this(config.getContext(), config.getName(), null, config.getVersion(), null);
		this.onSqliteListener = onSqliteListener;
	}
	
	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub
		if(onSqliteListener!=null){
			onSqliteListener.onCreate(db);
		}
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub
		if(onSqliteListener!=null){
			onSqliteListener.onUpdate(db, oldVersion, newVersion);
		}
	}
	
	/**
	 * 删除数据库
	 * @param path
	 */
	public static void delete(String path){
		SQLiteDatabase.deleteDatabase(new File(path));
	}
	
	/**
	 * 
	 * @param path
	 * @return
	 */
	public static SQLiteDatabase openReadOnly(String path){
		return SQLiteDatabase.openDatabase(path, new com.jingtuo.android.common.db.CursorFactory(), SQLiteDatabase.OPEN_READONLY, new com.jingtuo.android.common.db.DatabaseErrorHandler());
	}
	
	
	/**
	 * 
	 * @param path
	 * @return
	 */
	public static SQLiteDatabase openReadWrite(String path){
		return SQLiteDatabase.openDatabase(path, new com.jingtuo.android.common.db.CursorFactory(), SQLiteDatabase.OPEN_READWRITE, new com.jingtuo.android.common.db.DatabaseErrorHandler());
	}
	
	/**
	 * 创建的数据库版本缺省值为0
	 * @param path
	 * @return
	 */
	private static SQLiteDatabase create(String path){
		return SQLiteDatabase.openOrCreateDatabase(path, new com.jingtuo.android.common.db.CursorFactory(), new com.jingtuo.android.common.db.DatabaseErrorHandler());
//		return SQLiteDatabase.openOrCreateDatabase(path, null, null);
	}
	
	
	/**
	 * 
	 * @param config 必须设置:context,path,version
	 * @param onSqliteListener
	 */
	public static void create(SqliteConfig config, OnSqliteListener onSqliteListener){
		if (config == null) {
			return;
		}
		File file = new File(config.getPath());
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		SQLiteDatabase database = create(config.getPath());
		if (config.getVersion() == 1) {// create
			if(database.getVersion()==0){//数据库刚创建
				database.beginTransaction();
				if (onSqliteListener != null) {
					onSqliteListener.onCreate(database);
				}
				database.setVersion(config.getVersion());
				database.setTransactionSuccessful();
				database.endTransaction();
				database.close();
			}
		} else if(config.getVersion() > 1) {// update
			database.beginTransaction();
			if (onSqliteListener != null) {
				onSqliteListener.onUpdate(database, database.getVersion(),
						config.getVersion());
			}
			database.setVersion(config.getVersion());
			database.setTransactionSuccessful();
			database.endTransaction();
			database.close();
		}
	}
	
	/**
	 * 创建表,方法内部不开启事务
	 * @param database
	 * @param table
	 */
	public static <T> void createTable(SQLiteDatabase database, Class<T> table){
		Table aTable = table.getAnnotation(Table.class);
		if(aTable!=null){
			String tableName = table.getSimpleName();
			String primaryKey = getPrimaryKey(table.getAnnotation(Table.class));
			StringBuffer sqlBuffer = new StringBuffer();
			sqlBuffer.append("CREATE TABLE IF NOT EXISTS " + tableName);
			StringBuffer columnBuffer = new StringBuffer();
			Field[] fields = table.getDeclaredFields();
			if(fields!=null){
				Column column = null;
				Field field = null;
				for (int i = 0; i < fields.length; i++) {
					field = fields[i];
					column = field.getAnnotation(Column.class);
					if(column.version()==1){//选择初始版本字段进行创建
						String columnName = fields[i].getName();
						if(columnName!=null){
							columnBuffer.append(columnName + " ");
							String dataType = getDataType(field.getType());
							columnBuffer.append(dataType + ",");
						}
					}
				}
			}
			String columns = columnBuffer.toString();
			if(columns.length()>0){
				columns = columns.substring(0, columns.length()-1);
				sqlBuffer.append("(");
				sqlBuffer.append(columns);
				if(primaryKey!=null&&!primaryKey.equals("")){
					sqlBuffer.append(", PRIMARY KEY(" + primaryKey + ")");
				}
				sqlBuffer.append(");");
				String sql = sqlBuffer.toString();
				LogUtils.debug(TAG, sql);
				database.execSQL(sql);
			}
		}
	}
	
	/**
	 * 删除表,方法内部不开启事务
	 * @param database
	 * @param table
	 */
	public static <T> void dropTable(SQLiteDatabase database, Class<T> table){
		Table aTable = table.getAnnotation(Table.class);
		if(aTable!=null){
			String tableName = table.getSimpleName();
			if(tableName!=null){
				String sql = "DROP TABLE IF EXISTS " + tableName + ";";
				LogUtils.debug(TAG, sql);
				database.execSQL(sql);
			}
		}
	}

	public static <T> void addColumns(SQLiteDatabase database, int version, Class<T> table){
		
	}
	
	
	/**
	 * 
	 * @param path
	 * @param obj
	 */
	public static void insert(String dbPath, Object obj){
		Class<?> cTable = obj.getClass();
		Table aTable = cTable.getAnnotation(Table.class);
		if(aTable!=null){//插入的数据对象所对应的类是一张表
			SQLiteDatabase database = openReadWrite(dbPath);
			if(database!=null){
				String tableName = cTable.getSimpleName();
				try {
					database.beginTransaction();
					database.insert(tableName, null, toContentValues(obj));
					database.setTransactionSuccessful();
				} catch (Exception e) {
					saveExceptionInfo(dbPath, e);
				} finally{
					database.endTransaction();
					database.close();
				}
			}
		}
	}
	
	/**
	 * 获取表的主键
	 * @param table
	 * @return
	 */
	private static String getPrimaryKey(Table table){
		String primaryKey = null;
		if(table!=null){
			primaryKey = table.primaryKey();
		}
		return primaryKey;
	}
	
	private static String getDataType(Class<?> cls){
		String dataType = DATA_TYPE_TEXT;
		if(Date.class.equals(cls)||String.class.equals(cls)){
			dataType = DATA_TYPE_TEXT;
		}else if(Integer.class.equals(cls)||"int".equals(cls.getName())||Boolean.class.equals(cls)||"boolean".equals(cls.getName())){
			dataType = DATA_TYPE_INTEGER;
		}else if(Double.class.equals(cls)||"double".equals(cls.getName())||Float.class.equals(cls)||"float".equals(cls.getName())){
			dataType = DATA_TYPE_REAL;
		}else if("byte[]".equals(cls.getName())){
			dataType = DATA_TYPE_BLOD;
		}
		return dataType;
	}
	
	/**
	 * 保存异常信息
	 * @param throwable
	 */
	public static void saveExceptionInfo(String dbPath, Throwable throwable){
		StringWriter writer = new StringWriter();
		throwable.printStackTrace(new PrintWriter(writer));
		String content = writer.toString();
		ExceptionInfo exceptionInfo = new ExceptionInfo();
		exceptionInfo.setBrand(Build.BRAND);
		exceptionInfo.setContent(content);
		exceptionInfo.setModel(Build.MODEL);
		exceptionInfo.setOccurTime(new Date(System.currentTimeMillis()));
		exceptionInfo.setProduct(Build.PRODUCT);
		exceptionInfo.setUser(Build.USER);
		exceptionInfo.setVersionIncremental(Build.VERSION.INCREMENTAL);
		exceptionInfo.setVersionRelease(Build.VERSION.RELEASE);
		exceptionInfo.setVersionSdk(Build.VERSION.SDK_INT);
		insert(dbPath, exceptionInfo);
	}
	
	/**
	 * 将数据对象转换成ContentValues
	 * @param obj
	 * @return
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	private static <T> ContentValues toContentValues(Object obj) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		ContentValues values = new ContentValues();
		Class<?> cls = obj.getClass();
		Field[] fields = cls.getDeclaredFields();
		if(fields!=null){
			Field field = null;
			Column column = null;
			String columnName = null;
			Method method = null;
			for (int i = 0; i < fields.length; i++) {
				field = fields[i];
				column = field.getAnnotation(Column.class);
				if(column!=null){
					columnName = field.getName();
					Class<?> cType =  field.getType();
					method =  cls.getDeclaredMethod("get" + StringHeper.firstToUpper(columnName), new Class[0]);
					if(Date.class.equals(cType)){
						Date date =(Date) method.invoke(obj, new Object[0]);
						values.put(columnName, DateTimeHelper.toString(date, DateTimeHelper.yyyy_MM_dd_HH_mm_ss_SSS));
					}else if(String.class.equals(cType)){
						String value = (String)method.invoke(obj, new Object[0]);
						values.put(columnName, value);
					}else if(Integer.class.equals(cType)||"int".equals(cType.getName())){
						Integer value = (Integer)method.invoke(obj, new Object[0]);
						values.put(columnName, value);
					}else if(Boolean.class.equals(cls)||"boolean".equals(cls.getName())){
						Boolean value = (Boolean)method.invoke(obj, new Object[0]);
						values.put(columnName, value.booleanValue()?1:0);
					}else if(Double.class.equals(cType)||"double".equals(cls.getName())){
						Double value = (Double)method.invoke(obj, new Object[0]);
						values.put(columnName, value);
					} else if(Float.class.equals(cls)||"float".equals(cls.getName())){
						Float value = (Float)method.invoke(obj, new Object[0]);
						values.put(columnName, value);
					}else if("byte[]".equals(cls.getName())){
						byte[] value = (byte[])method.invoke(obj, new Object[0]);
						values.put(columnName, value);
					}
				}
			}
		}
		return values;
	}
	
}
